qactors is package{
  -- test out ideas for doing the actor transformation in star code; not macros.
  import treemap;
    
  type eRule is eRule(string,quoted,quoted,quoted);
  
  channelId(eRule(N,_,_,_)) is N;
  
  -- manage the transformation of actors
  trActor(quote(actor{?Defs})) is quote(act0r({?actorTheta(Defs)}));
  
  actorTheta(Defs) is buildActorTheta(unwrap(Defs,pickEvtRule,(nil,nil))) using {
    pickEvtRule(<|on ?Ptn on ?Ch where ?Cond do ?Act|>,(Rules,Others)) is (cons(eRule(getId(Ch),Ptn,Cond,Act),Rules),Others);
    pickEvtRule(<|on ?Ptn on ?Ch do ?Act|>,(Rules,Others)) is (cons(eRule(getId(Ch),Ptn,quote(true),Act)),Rules),Others);
    pickEvtRule(Stmt,(Rules,Others)) is (Rules,cons(Stmt,Others));
  };
 
  buildActorTheta((Rules,Others)) is makeRules(sortRules(Rules),Others);
  
  -- sort rules by channel
  sortRules(Rules) is valof{
    var RuleMap := treemap of {};
    for Rl in Rules do{
      var chnnl is channelId(Rl);
      var SubRules is RuleMap[chnnl] default cons of {};
      RuleMap[chnnl] := cons of {Rl;..SubRules};
    }
    valis RuleMap;
  }
  
  


  -- make eca rules from sorted groups
  #makeRules(((?Ch,?Rules),?More),?Others) ==>  makeRules(More,glom(makeEcaProc(Ch,channelProc(Rules,(), #$"evt"),#$"evt"),Others));
  #makeRules((?Ch,?Rules),()) ==> makeEcaProc(Ch,channelProc(Rules,(), #$"evt"),#$"evt");
  #makeRules((?Ch,?Rules),?Others) ==> glom(makeEcaProc(Ch,channelProc(Rules,(), #$"evt"),#$"evt"),Others);
  #makeRules((),?Others) ==> Others;
  
  -- construct the channel procedure
  
 
  
  -- We create a procedure for each channel
  channelProc(loc,Chnnl,Rules) is channelRules(Rules) using {
    EventVar is nameAst(loc,genSym("evt"));
    
    -- And a procedure is created for each event rule.
    channelRule(eRule(Chnl,Ptn,Cond,Action)) is (<|?Head where ?Cond do ?Action|>,invoker) using{
      loc is locationOf(Action);
      Head is applyAst(loc,LclName,list{Ptn});
      LclName is nameAst(loc,gensym("eca"));
      invoker is applyAst(loc,LclName,list{EventVar});
    }
    
    channelRules(Rls) is valof{
      LL is all channelRule(Rl) where Rl in Rls;

      var CC := quote(nothing);
      var RR := quote(nothing);
      for (Rl,I) in LL do{
        if CC=quote(nothing) then{
          CC := I;
          RR := Rl;
        }
        else{
          CC := <|?I;?CC|>;
          RR := <|?Rl;?RR|>;
        }
      }
      
      valis <| ?applyAst(loc,nameAst(loc,Chnnl),list{EventVar}) do {?CC} using {?RR}|>
    };
  };

  #channelProc(eRule(?Ch,?P,?C,?A),(),?Evt) ==> 
     (#( #(#$"eca")#(P) where C do A)#, #(#$"eca")#(Evt));
  #channelProc(eRule(?Ch,?P,?C,?A),(?Defs,?Calls),?Evt) ==> 
     (#( #(#$"eca")#(P) where C do A;Defs)#,#( #(#$"eca")#(Evt);Calls)#);
  #channelProc((eRule(?Ch,?P,?C,?A),?More),(),?Evt) ==> 
     channelProc(More,(#( #(#$"eca")#(P) where C do A)#, #(#$"eca")#(Evt)),Evt);
  #channelProc((eRule(?Ch,?P,?C,?A),?More),(?Defs,?Calls),?Evt) ==> 
     channelProc(More,( #( #(#$"eca")#(P) where C do A;Defs)#,#( #(#$"eca")#(Evt) ;Calls)#),Evt);
  
  #makeEcaProc(?Ch, (?Defs, ?Calls), ?Evt) ==> #( Ch(Evt) do {Calls} using { Defs } )#;  
  
  
  -- utility functions
  unwrap(<|?L;?R|>,F,S) is unwrap(R,F,unwrap(L,F,S));
  unwrap(St,F,S) is F(St,S);
}
  
  